package org.hong.monkey

import java.util.concurrent.CopyOnWriteArrayList

import org.hong.monkey.util.Utils

import scala.reflect.ClassTag
import scala.collection.JavaConverters._
import scala.util.control.NonFatal

private[monkey] trait ListenerBus[L <: AnyRef, E] extends Logging {

  private[monkey] val listeners = new CopyOnWriteArrayList[L]

  final def addListener(listener: L) {
    listeners.add(listener)
  }

  final def postToAll(event: E): Unit = {
    val iter = listeners.iterator
    while (iter.hasNext) {
      val listener = iter.next()
      try {
        onPostEvent(listener, event)
      } catch {
        case NonFatal(e) =>
          logError(s"Listener ${Utils.getFormattedClassName(listener)} threw an exception", e)
      }
    }
  }

  def onPostEvent(listener: L, event: E): Unit

  private[monkey] def findListenersByClass[T <: L : ClassTag](): Seq[T] = {
    val c = implicitly[ClassTag[T]].runtimeClass
    listeners.asScala.filter(_.getClass == c).map(_.asInstanceOf[T]).toSeq
  }
}
